package com.singbon.server.config;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.refresh.ContextRefresher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;
/**
 */
@Configuration
@EnableAuthorizationServer
@Slf4j
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
  private static final String CLIENT_SECRET = "123456";
  /**
   * password
   * implicit
   * client_credentials
   * authorization_code
   */
  private static final String[] CLIENT_GRANT_TYPES = {"authorization_code", "refresh_token", "password"};
  private final Environment env;
  private final ContextRefresher contextRefresher;
  private final PasswordEncoder passwordEncoder;
  @Autowired
  public AuthorizationServerConfig(ContextRefresher contextRefresher, Environment env, PasswordEncoder passwordEncoder) {
    this.contextRefresher = contextRefresher;
    this.env = env;
    this.passwordEncoder = passwordEncoder;
  }
  @Override
  public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    contextRefresher.refresh();
    String[] activeProfiles = env.getActiveProfiles();
    log.info("activeProfiles:" + JSON.toJSONString(activeProfiles));
    String clientId1 = "xb";
    String clientId2 = "su";
    String clientId3 = "balance";
    String clientId4 = "device";
    String clientId5 = "prototype";
    String[] redirectUris = getRedirectUris();
    // 定义了两个客户端应用的通行证
    // 使用in-memory存储
    clients.inMemory()
      // xb 后台 /////////////////////////////////////
      .withClient(clientId1).secret(passwordEncoder.encode(CLIENT_SECRET)).authorizedGrantTypes(CLIENT_GRANT_TYPES).scopes("all").autoApprove(true).redirectUris(redirectUris).and()
      // su
      .withClient(clientId2).secret(passwordEncoder.encode(CLIENT_SECRET)).authorizedGrantTypes(CLIENT_GRANT_TYPES).scopes("all").autoApprove(true).redirectUris(redirectUris).and()
      // balance
      .withClient(clientId3).secret(passwordEncoder.encode(CLIENT_SECRET)).authorizedGrantTypes(CLIENT_GRANT_TYPES).scopes("all").autoApprove(true).redirectUris(redirectUris).and()
      // device
      .withClient(clientId4).secret(passwordEncoder.encode(CLIENT_SECRET)).authorizedGrantTypes(CLIENT_GRANT_TYPES).scopes("all").autoApprove(true).redirectUris(redirectUris).and()
      // prototype
      .withClient(clientId5).secret(passwordEncoder.encode(CLIENT_SECRET)).authorizedGrantTypes(CLIENT_GRANT_TYPES).scopes("all").autoApprove(true).redirectUris(redirectUris);
  }
  @Override
  public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
    //endpoints.tokenStore(jwtTokenStore()).accessTokenConverter(jwtAccessTokenConverter())
    DefaultTokenServices tokenServices = (DefaultTokenServices) endpoints.getDefaultAuthorizationServerTokenServices();
    //tokenServices.setTokenStore(endpoints.getTokenStore())
    tokenServices.setTokenStore(jwtTokenStore());
    tokenServices.setSupportRefreshToken(true);
    tokenServices.setClientDetailsService(endpoints.getClientDetailsService());
    //tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer())
    tokenServices.setTokenEnhancer(jwtAccessTokenConverter());
    // 一分钟有效期
    tokenServices.setAccessTokenValiditySeconds((int) TimeUnit.MINUTES.toSeconds(10));
    endpoints.tokenServices(tokenServices);
  }
  @Override
  public void configure(AuthorizationServerSecurityConfigurer security) {
    security.tokenKeyAccess("isAuthenticated()");
  }
  @Bean
  public TokenStore jwtTokenStore() {
    return new JwtTokenStore(jwtAccessTokenConverter());
  }
  @Bean
  public JwtAccessTokenConverter jwtAccessTokenConverter() {
    ClassPathResource classPathResource = new ClassPathResource("jks.jks");
    // "testpass".toCharArray())
    char[] pdwChars = "xb_bs_card_union".toCharArray();
    KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(classPathResource, pdwChars);
    //
    JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
    converter.setSigningKey("ycsty");
    converter.setKeyPair(keyStoreKeyFactory.getKeyPair("xb_bs_card_union"));
    log.info(converter.toString());
    return converter;
  }
  /**
   * OAuth Error
   * error="invalid_grant", error_description="
   * Invalid redirect: http://192.168.10.182:8083/login does not match one of the registered values."
   *
   * @return String[]
   */
  public String[] getRedirectUris() {
    int registerRedirectUriCount;
    String registerRedirect0 = env.getProperty("register-redirect-0");
    if (StringUtils.isEmpty(registerRedirect0)) {
      registerRedirect0 = "50";
    }
    log.info("just for use {}", registerRedirect0);
    registerRedirectUriCount = Integer.parseInt(registerRedirect0);
    String[] registerRedirectUris = new String[registerRedirectUriCount];
    for (int i = 0; i < registerRedirectUriCount; i++) {
      String registerRedirectX = env.getProperty("register-redirect-" + i);
      if (StringUtils.isEmpty(registerRedirectX)) {
        log.warn("授权注册地址为空跳过 empty register redirect :i={},register-redirect-{}", i, i);
        continue;
      }
      registerRedirectUris[i] = registerRedirectX;
    }
    return registerRedirectUris;
  }
}